package com.kl.exception;

import com.kl.model.R;
import com.kl.enums.ErrorCodeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.HashMap;
import java.util.Map;

/**
 * 全局异常处理器
 */
@Slf4j
@RestControllerAdvice(basePackages = "com.kl.controller")
public class ExceptionControllerAdvice {

    /**
     * 如果能精确匹配具体的异常就会走具体的异常处理流程
     * 如果不能匹配具体的异常就走全局处理流程
     */

    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public R handleValidException(MethodArgumentNotValidException e) {
        log.error("数据校验出现的问题：{}，异常类型：{}", e.getMessage(), e.getClass());
        // 获取到具体的错误信息封装类
        BindingResult bindingResult = e.getBindingResult();
        Map<String, String> errorMap = new HashMap<>();
        // 获取到每一个校验失败的属性明和对应的错误信息
        bindingResult.getFieldErrors().forEach(fieldError -> {
            errorMap.put(fieldError.getField(), fieldError.getDefaultMessage());
        });
        // 为什么要使用枚举类来传入错误码和错误信息了
        // 第一：这是一种规范，对于具体发生的错误怎么返回应该是公司规定好的，整个业务都要按规定的返回
        // 第二：不用硬编码的形式，方便后期统一的修改
        return R.error(ErrorCodeEnum.VALID_EXCEPTION.getCode(),
                ErrorCodeEnum.VALID_EXCEPTION.getErrMsg()).put("data", errorMap);
    }

    /**
     * 处理最大的异常，默认的异常处理
     */
    @ExceptionHandler(value = Throwable.class)
    public R handleException() {
        return R.error(ErrorCodeEnum.UNKNOWN_EXCEPTION.getCode(),
                ErrorCodeEnum.UNKNOWN_EXCEPTION.getErrMsg());
    }
}
